package cs342.uwosh.edu.MyWorldApp.misc;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

/*
 * 		This class might be useful for methods that run in the background.
 * OR
 * 		This class might be useless
 */

//TODO Discuss how background thread should be implemented

public class BackgroundMethod<T> extends AsyncMethod<T> 
{

	@SuppressWarnings("rawtypes")
	public static ArrayList<BackgroundMethod> threads;
	
	private long sleepInterval;
	private boolean finished;
	
	/**
	 * Constructor
	 * 
	 * @param objectClass - the class that contains the method
	 * @param object - the object that the method will be invoked from
	 * @param methodName - the method to be executed in thread
	 * @param sleepInterval - method will be called after every sleepInterval
	 */
	
	@SuppressWarnings("rawtypes")
	public BackgroundMethod(Class<T> objectClass, T object, String methodName, long sleepInterval) {
		super(objectClass, object, methodName);
		if(threads == null) {
			threads = new ArrayList<BackgroundMethod>();
		}
		threads.add(this);
		this.sleepInterval = sleepInterval;
		this.finished = false;
	}
	
	public Object doInBackground(Object... args)
	{
		@SuppressWarnings("rawtypes")
		Class[] argClasses = new Class[args.length];
		for(int i = 0; i < args.length; i++) {
			argClasses[i] = args[i].getClass();
		}
		
		Method method = null;
		try {
			method = getObjectClass().getMethod(getMethodName(), argClasses);
		} catch (SecurityException e1) {
			e1.printStackTrace();
		} catch (NoSuchMethodException e1) {
			e1.printStackTrace();
		}
		
		Object obj = null;
		try {
			Object object = getObject();
			while(!finished) {
				wait(sleepInterval);
				method.invoke(object, args);
			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return obj;
	}
	
	public Object finish() {
		finished = true;
		return getResult();
	}
	
	// Should be used once main program is finished
	public static void finishAll() {
		if(threads != null) {
			@SuppressWarnings("rawtypes")
			BackgroundMethod method;
			while(!threads.isEmpty()) {
				method = threads.get(0);
				method.finish();
				threads.remove(0);
			}
		}
	}
	
	public static void forceUpdateAll() {
		if(threads != null) {
			@SuppressWarnings("rawtypes")
			BackgroundMethod method;
			while(!threads.isEmpty()) {
				method = threads.get(0);
				method.notify();
				threads.remove(0);
			}
		}
	}
}
